package com.binance.sysconf.service;

import com.alibaba.fastjson.JSON;
import com.binance.master.utils.StringUtils;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Description: 系统配置缓存服务
 *
 * @author hongchaoMao - Date 2018/7/23
 */
public class SysConfigVarCacheService {

    private static Log log = LogFactory.getLog(SysConfigVarCacheService.class);

    private final static String SWITCH = "apollo_config";
    private final static String NAME_SPACE = "biz.common-config";

    private Map<String, String> cache = new ConcurrentHashMap<>();

    private JdbcTemplate oldJdbcTemplate;

    public SysConfigVarCacheService(JdbcTemplate oldJdbcTemplate) {
        this.oldJdbcTemplate = oldJdbcTemplate;
    }

    /**
     * Discription: Get system config string value.
     *
     * @param key the key
     * @return the string (return null if the key not config)
     * @author hongchaoMao - Date 2018-7-25
     */
    public String getValue(String key) {
        if (cache.size() == 0) {
            init();
        }

        // 从Apollo读取配置信息
        String isApolloOn = cache.get(SWITCH);
        if ("Y".equalsIgnoreCase(isApolloOn)) {
            Config config = ConfigService.getConfig(NAME_SPACE);
            String value = config.getProperty(key, StringUtils.EMPTY);
            if (!cache.get(key).equalsIgnoreCase(value)) {
                log.warn("the values of sysConfig and apollo are not the same");
            }
            return value;
        }

        return cache.get(key);
    }

    /**
     * Discription: Get system config integer value.
     *
     * @param key the key
     * @return the string (return null if the key not config)
     * @author hongchaoMao - Date 2018-7-25
     */
    public Integer getInteger(String key) {
        String val = getValue(key);
        if (!Objects.isNull(val)) {
            return Integer.parseInt(val);
        }
        return null;
    }

    /**
     * Discription: Get long value.
     *
     * @param key the key
     * @return the long (return null if the key not config)
     * @author hongchaoMao - Date 2018-7-25
     */
    public Long getLong(String key) {
        String val = getValue(key);
        if (!Objects.isNull(val)) {
            return Long.parseLong(val);
        }
        return null;
    }

    /**
     * Discription: Get double value.
     *
     * @param key the key
     * @return the double (return null if the key not config)
     * @author hongchaoMao - Date 2018-7-25 19:11:38
     */
    public Double getDouble(String key) {
        String val = getValue(key);
        if (!Objects.isNull(val)) {
            return Double.parseDouble(val);
        }
        return null;
    }

    /**
     * Discription: Get boolean value.
     *
     * @param key the key
     * @return the boolean (return null if the key not config)
     * @author hongchaoMao - Date 2018-7-25
     */
    public Boolean getBoolean(String key) {
        String val = getValue(key);
        if (!Objects.isNull(val)) {
            return Boolean.valueOf(val);
        }
        return null;
    }

    /**
     * get list value
     *
     * @param key the key
     * @param cls the class type
     * @return a list (not null)
     */
    public <T> List<T> getList(String key, Class<T> cls) {
        String val = getValue(key);
        if (StringUtils.isNotBlank(val)) {
            return JSON.parseArray(val, cls);
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * get list value
     *
     * @param key the key
     * @return a list (not null)
     */
    public List getList(String key) {
        String val = getValue(key);
        if (StringUtils.isNotBlank(val)) {
            return JSON.parseArray(val);
        } else {
            return Collections.emptyList();
        }
    }

    /**
     * get map value
     *
     * @param key the key
     * @return map (not null)
     */
    public Map getMap(String key) {
        String val = getValue(key);
        if (StringUtils.isNotBlank(val)) {
            return JSON.parseObject(val);
        } else {
            return Collections.emptyMap();
        }
    }


    /**
     * Discription: Modify single val.
     *
     * @param key the key
     * @param val the val
     * @author hongchaoMao - Date 2018-7-25
     */
    void modifyVal(String key, String val) {
        cache.put(key, val);
    }

    /**
     * Discription: Refresh cache.
     *
     * @author hongchaoMao - Date 2018-7-25 11:43:46
     */
    void refresh() {
        cache.clear();
        init();
    }

    /**
     * Discription: Init cache.
     *
     * @author hongchaoMao - Date 2018-7-25 11:43:39
     */
    synchronized void init() {
        // 避免refresh()和getValue()同时调用而初始化两次
        if (cache.size() != 0) {
            return;
        }
        try {
            String sql = "SELECT DISPLAY_NAME, CODE FROM SYS_CONFIG";
            List<Integer> result = oldJdbcTemplate.query(sql, (resultSet, i) -> {
                String key = resultSet.getString("DISPLAY_NAME");
                String val = resultSet.getString("CODE");
                if (key != null && val != null) {
                    cache.put(key, val);
                }
                return i;
            });
            if (result.size() > 0) {
                log.info("------>init() Database config variable init finished !");
            }
        } catch (Exception e) {
            log.error("系统配置变量初始化异常: ", e);
        }
    }
}